//Copyright(c) Hugh Greenberg

//Based of Tutorial from: http://insanitydesign.com/wp/projects/nehe-android-ports/
package com.hugegreenbug.msoss;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;

import com.hugegreenbug.msoss.WikiCommonsImage;

import android.util.Log;


public class Cube {
	private FloatBuffer vertexBuf;
	private FloatBuffer texBuf;
	private ByteBuffer indexBuf;
	private int[] textures = new int[1];
	private boolean mTextureSet = false;
	private boolean mScale = true;
	private WikiCommonsImage mWi;
	private FloatBuffer normBuf;
	private float vertices[] = {
			//Front Face
			-1.0f, -1.0f, 1.0f,
			1.0f, -1.0f, 1.0f,
			-1.0f, 1.0f, 1.0f,
			1.0f, 1.0f, 1.0f,
			
			//Right Face
			1.0f, -1.0f, 1.0f,
			1.0f, -1.0f, -1.0f,
			1.0f, 1.0f, 1.0f,
			1.0f, 1.0f, -1.0f,
			
			//Back Face
			1.0f, -1.0f, -1.0f,
			-1.0f, -1.0f, -1.0f,
			1.0f, 1.0f, -1.0f,
			-1.0f, 1.0f, -1.0f,
	
			//Left Face
			-1.0f, -1.0f, -1.0f,
			-1.0f, -1.0f, 1.0f,
			-1.0f, 1.0f, -1.0f,
			-1.0f, 1.0f, 1.0f,
			
			//Bottom Face
			-1.0f, -1.0f, -1.0f,
			1.0f, -1.0f, -1.0f,
			-1.0f, -1.0f, 1.0f,
			1.0f, -1.0f,  1.0f,

    		//Top Face
			-1.0f, 1.0f, 1.0f,
			1.0f, 1.0f, 1.0f,
			-1.0f, 1.0f, -1.0f,
			1.0f, 1.0f, -1.0f,
	};
	
	private float[] texcoords  = {
			//Front Face
			0.0f, 0.0f,
    		1.0f, 0.0f,
    		0.0f, 1.0f,
    		1.0f, 1.0f, 
    		
    		//Right Face
    		0.0f, 0.0f,
    		1.0f, 0.0f,
    		0.0f, 1.0f,
    		1.0f, 1.0f,
			
    		//Back Face
    		0.0f, 0.0f,
    		1.0f, 0.0f,
    		0.0f, 1.0f,
    		1.0f, 1.0f,
    		
    		//Left Face
    		0.0f, 0.0f,
    		1.0f, 0.0f,
    		0.0f, 1.0f,
    		1.0f, 1.0f,
    		
    		//Bottom Face	
    		0.0f, 0.0f,
    		1.0f, 0.0f,
    		0.0f, 1.0f,
    		1.0f, 1.0f,
    		
    		//Top Face
    		0.0f, 0.0f,
    		1.0f, 0.0f,
    		0.0f, 1.0f,
    		1.0f, 1.0f,
	};
	
	private byte[] indicies = {
			0, 1, 3,    0, 3, 2,       //Front Face
			4, 5, 7,    4, 7, 6,       //Right Face
			8, 9, 11,   8, 11, 10,     //Back Face
			12, 13, 15, 12, 15, 14,    //Left Face
			16, 17, 19,   16, 19, 18,  //Bottom Face
			20, 21, 23,  20, 23, 22    //Top Face			
	};
	
	private float normals[] = {
			//Front Face
			0.0f, 0.0f, 5.0f, 						
			0.0f, 0.0f, 5.0f, 
			0.0f, 0.0f, 5.0f, 
			0.0f, 0.0f, 5.0f, 
			
			//Right Face
			5.0f, 0.0f, 0.0f, 
			5.0f, 0.0f, 0.0f, 
			5.0f, 0.0f, 0.0f, 
			5.0f, 0.0f, 0.0f,
			
			//Back Face
			0.0f, 0.0f, -5.0f, 
			0.0f, 0.0f, -5.0f, 
			0.0f, 0.0f, -5.0f, 
			0.0f, 0.0f, -5.0f,
			
			//Left Face
			-5.0f, 0.0f, 0.0f, 
			-5.0f, 0.0f, 0.0f, 
			-5.0f, 0.0f, 0.0f, 
			-5.0f, 0.0f, 0.0f,
			
			//Bottom Face
			0.0f, -5.0f, 0.0f, 
			0.0f, -5.0f, 0.0f, 
			0.0f, -5.0f, 0.0f, 
			0.0f, -5.0f, 0.0f,
			
    		//Top Face
			0.0f, 5.0f, 0.0f, 
			0.0f, 5.0f, 0.0f, 
			0.0f, 5.0f, 0.0f, 
			0.0f, 5.0f, 0.0f,
	};

	
	public Cube() {
		ByteBuffer buf = ByteBuffer.allocateDirect(vertices.length * 4);
		buf.order(ByteOrder.nativeOrder());
		vertexBuf = buf.asFloatBuffer();
		vertexBuf.put(vertices);
		vertexBuf.position(0);
		
		buf = ByteBuffer.allocateDirect(texcoords.length * 4);
		buf.order(ByteOrder.nativeOrder());
		texBuf = buf.asFloatBuffer();
		texBuf.put(texcoords);
		texBuf.position(0);
		
		buf = ByteBuffer.allocateDirect(indicies.length);
		buf.order(ByteOrder.nativeOrder());
		indexBuf = buf;
		indexBuf.put(indicies);
		indexBuf.position(0);
		
		buf = ByteBuffer.allocateDirect(normals.length * 4);
		buf.order(ByteOrder.nativeOrder());
		normBuf = buf.asFloatBuffer();
		normBuf.put(normals);
		normBuf.position(0);
	
		mWi = null;
		textures[0] = -1;
	}
	
	public void init(GL10 gl) {
		if (textures[0] < 0)
			gl.glGenTextures(1, textures, 0);
	}
	
	public void draw(GL10 gl) {
		if (!mTextureSet)
			return;
		
		try {
			gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
			gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
			gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
			gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
			
			gl.glFrontFace(GL10.GL_CCW);
		
			gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuf);
			gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texBuf);
			gl.glNormalPointer(GL10.GL_FLOAT, 0, normBuf);
			gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_MODULATE);
			gl.glDrawElements(GL10.GL_TRIANGLES, indicies.length, GL10.GL_UNSIGNED_BYTE, indexBuf);
		
			gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
			gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
			gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
		} catch (Exception e) {
			Log.e("Musician Slideshow", "Error while drawing texture for cube");
		}
	}
			
	public void setTexture(GL10 gl, WikiCommonsImage wi, float width, float height, boolean scale) {
		if (mTextureSet) 
			return;
		
		if (wi == null || wi.getByteBuffer() == null)
			return;
		
		mScale = scale;
		mWi = wi;
		init(gl);
		setSize(width, height);
		gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
		if (gl instanceof GL11) {
			gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
			gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR_MIPMAP_NEAREST);
			gl.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_GENERATE_MIPMAP, GL11.GL_TRUE);
		} else {
			gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
			gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
		}
			
		gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_MODULATE);
		gl.glDisable(GL10.GL_BLEND);
		gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA, wi.getTexWidth(), wi.getTexHeight(),
			0, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, wi.getByteBuffer());
		mTextureSet = true;
	}
	
	public void setSize(float width, float height) {
		if (textures[0] < 0 || mWi == null)
			return;
		
		if (mScale) {
			//	float wscale = Math.round((float) wi.getScaledWidth()/width * 1000);
			float wscale = Math.round((float) mWi.getScaledWidth()/mWi.getScaledHeight() * 1000);
			while (wscale % 2 != 0) {
				wscale++;
			}
		
			wscale /= 1000;
			//float hscale = Math.round((float) wi.getScaledHeight()/height * 1000);
			float hscale = Math.round((float) mWi.getScaledHeight()/mWi.getScaledWidth() * 1000);
			while (hscale % 2 != 0) {
				hscale++;
			}
		
			hscale /= 1000;
			vertices[0] = -wscale;
			vertices[1] = -hscale;
			vertices[3] = wscale;
			vertices[4] = -hscale;
			vertices[6] = -wscale;
			vertices[7] = hscale;
			vertices[9] = wscale;
			vertices[10] = hscale;
		
			vertices[12] = wscale;
			vertices[13] = -hscale;
			vertices[15] = wscale;
			vertices[16] = -hscale;
			vertices[18] = wscale;
			vertices[19] = hscale;
			vertices[21] = wscale;
			vertices[22] = hscale;
		
			vertices[24] = wscale;
			vertices[25] = -hscale;
			vertices[27] = -wscale;
			vertices[28] = -hscale;
			vertices[30] = wscale;
			vertices[31] = hscale;
			vertices[33] = -wscale;
			vertices[34] = hscale;
			
			vertices[36] = -wscale;
			vertices[37] = -hscale;
			vertices[39] = -wscale;
			vertices[40] = -hscale;
			vertices[42] = -wscale;
			vertices[43] = hscale;
			vertices[45] = -wscale;
			vertices[46] = hscale;
			
			vertices[48] = -wscale;
			vertices[49] = -hscale;
			vertices[51] = wscale;
			vertices[52] = -hscale;
			vertices[54] = -wscale;
			vertices[55] = -hscale;
			vertices[57] = wscale;
			vertices[58] = -hscale;
			
			vertices[60] = -wscale;
			vertices[61] = hscale;
			vertices[63] = wscale;
			vertices[64] = hscale;
			vertices[66] = -wscale;
			vertices[67] = hscale;
			vertices[69] = wscale;
			vertices[70] = hscale;
		
		} else {
			vertices[0] = -1.0f;
			vertices[1] = -1.0f;
			vertices[3] = 1.0f;
			vertices[4] = -1.0f;
			vertices[6] = -1.0f;
			vertices[7] = 1.0f;
			vertices[9] = 1.0f;
			vertices[10] = 1.0f;
		
			vertices[12] = 1.0f;
			vertices[13] = -1.0f;
			vertices[15] = 1.0f;
			vertices[16] = -1.0f;
			vertices[18] = 1.0f;
			vertices[19] = 1.0f;
			vertices[21] = 1.0f;
			vertices[22] = 1.0f;
		
			vertices[24] = 1.0f;
			vertices[25] = -1.0f;
			vertices[27] = -1.0f;
			vertices[28] = -1.0f;
			vertices[30] = 1.0f;
			vertices[31] = 1.0f;
			vertices[33] = -1.0f;
			vertices[34] = 1.0f;
			
		
			vertices[36] = -1.0f;
			vertices[37] = -1.0f;
			vertices[39] = -1.0f;
			vertices[40] = -1.0f;
			vertices[42] = -1.0f;
			vertices[43] = 1.0f;
			vertices[45] = -1.0f;
			vertices[46] = 1.0f;
			
			vertices[48] = -1.0f;
			vertices[49] = -1.0f;
			vertices[51] = 1.0f;
			vertices[52] = -1.0f;
			vertices[54] = -1.0f;
			vertices[55] = -1.0f;
			vertices[57] = 1.0f;
			vertices[58] = -1.0f;
			
			vertices[60] = -1.0f;
			vertices[61] = 1.0f;
			vertices[63] = 1.0f;
			vertices[64] = 1.0f;
			vertices[66] = -1.0f;
			vertices[67] = 1.0f;
			vertices[69] = 1.0f;
			vertices[70] = 1.0f;
		}
		
		vertexBuf.clear();
		vertexBuf.put(vertices);
		vertexBuf.position(0);
	}
	
	public void releaseTextures(GL10 gl) {
		if (textures[0] > 0) {
			gl.glDeleteTextures(1, textures, 0);
			textures[0] = -1;
		}
		
		mWi = null;
		mTextureSet = false;
	}
}
